//////////////////////////////////////////////////////////////////////////////
// Boost.STL2 library
//
//  Copyright Fernando Pelliccioni 2012.
//  Use, modification and distribution is subject to the Boost Software
//  License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)


#ifndef string_range_HPP__
#define string_range_HPP__

#include <boost/assert.hpp>

//#include <boost/container/detail/config_begin.hpp>
//#include <boost/container/detail/workaround.hpp>
//
//#include <boost/container/detail/workaround.hpp>
//#include <boost/container/container_fwd.hpp>
//#include <boost/container/detail/utilities.hpp>
//#include <boost/container/detail/iterators.hpp>
//#include <boost/container/detail/algorithms.hpp>
//#include <boost/container/detail/version_type.hpp>
//#include <boost/container/detail/allocation_type.hpp>
//#include <boost/container/allocator/allocator_traits.hpp>
//#include <boost/container/detail/mpl.hpp>
//#include <boost/move/move.hpp>
//#include <boost/static_assert.hpp>
//
//#include <functional>
//#include <string>
//#include <stdexcept>      
//#include <utility>  
//#include <iterator>
//#include <memory>
//#include <algorithm>
//#include <iosfwd>
//#include <istream>
//#include <ostream>
//#include <ios>
//#include <locale>
//#include <cstddef>
//#include <climits>
//#include <boost/container/detail/type_traits.hpp>
//#include <boost/detail/no_exceptions_support.hpp>
//#include <boost/type_traits/has_trivial_destructor.hpp>
//#include <boost/aligned_storage.hpp>

namespace boost {
namespace container {

/// @cond
namespace container_detail {

	//! Const string_range used to iterate through a string. 
	template <class Pointer>
	class string_const_range
	{
	public:
		typedef std::random_access_iterator_tag                                          iterator_category;
		typedef typename boost::intrusive::pointer_traits<Pointer>::element_type         value_type;
		typedef typename boost::intrusive::pointer_traits<Pointer>::difference_type      difference_type;

		typedef typename boost::intrusive::pointer_traits<Pointer>::template 
			rebind_pointer<const value_type>::type										 pointer;

		typedef  const value_type&                                                       reference;

		/// @cond
	protected:
		Pointer begin_ptr_;
		Pointer end_ptr_;

	public:
		//Pointer get_ptr() const    
		//{
		//	return begin_ptr_;
		//}

		explicit string_const_range(Pointer begin_ptr, Pointer end_ptr)  
			: begin_ptr_(begin_ptr), end_ptr_(end_ptr)
		{}
		/// @endcond

	public:

		//Constructors
		string_const_range() 
			: begin_ptr_(nullptr), end_ptr_(nullptr)
		{}

		//Note: necesario para compatibilidad con C++11 range-based for
		Pointer begin() const
		{
			return begin_ptr_;
		}

		Pointer end() const
		{
			return end_ptr_;
		}

		difference_type size() const
		{
			return end_ptr_ - begin_ptr_;
		}

		bool empty() const
		{
			//return begin_ptr_ == end_ptr_;
			return begin_ptr_ >= end_ptr_;
		}


		//TODO: ver
		//operator unspecified_bool_type() const
		//{
		//	return safe_bool_t::to_unspecified_bool(m_Begin != m_End, &iterator_range::m_Begin);
		//}

		bool operator!() const
		{
			return empty();
		}

		bool equal( string_const_range const& r ) const
		{
			return begin_ptr_ == r.begin_ptr_ && end_ptr_ == r.end_ptr_;
		}


		////Pointer like operators
		//reference operator*()   const  
		//{
		//	return *begin_ptr_;
		//}

		//const value_type * operator->()  const  
		//{
		//	return container_detail::to_raw_pointer(begin_ptr_);
		//}

		reference front() const
		{
			BOOST_ASSERT( !empty() );
			return *begin_ptr_;
		}

		reference back() const
		{
			BOOST_ASSERT( !empty() );
			auto last( end_ptr_ );
			return *--last;
		}

		// pop_front() - added to model the SinglePassRangePrimitiveConcept
		void pop_front()
		{
			BOOST_ASSERT( !empty() );
			++begin_ptr_;
		}

		// pop_back() - added to model the BidirectionalRangePrimitiveConcept
		void pop_back()
		{
			BOOST_ASSERT( !empty() );
			--end_ptr_;
		}

		reference operator[](difference_type off) const
		{
			BOOST_ASSERT( off >= 0 && off < size() );
			return begin_ptr_[off];
		}

		//TODO: ver si hay que implementarlo...
		////
		//// When storing transform iterators, operator[]()
		//// fails because it returns by reference. Therefore
		//// operator()() is provided for these cases.
		////
		//abstract_value_type operator()( difference_type at ) const
		//{
		//	BOOST_ASSERT( at >= 0 && at < size() );
		//	return m_Begin[at];
		//}


		////Increment / Decrement
		//string_const_range& operator++()       
		//{
		//	++begin_ptr_;
		//	return *this;
		//}

		//string_const_range operator++(int)      
		//{
		//	Pointer tmp = begin_ptr_;
		//	++*this;
		//	return string_const_range(tmp);
		//}

		//string_const_range& operator--()
		//{
		//	--begin_ptr_;
		//	return *this;
		//}

		//string_const_range operator--(int)
		//{
		//	Pointer tmp = begin_ptr_;
		//	--*this;
		//	return string_const_range(tmp);
		//}

		//Arithmetic
		//string_const_range& operator+=(difference_type off)
		//{
		//	begin_ptr_ += off;
		//	return *this;
		//}

		string_const_range& advance_begin( difference_type off )
		{
			std::advance( begin_ptr_, off );
			return *this;
		}

		string_const_range& advance_end( difference_type off )
		{
			std::advance( end_ptr_, off );
			return *this;
		}


		string_const_range operator+(difference_type off) const
		{
			return string_const_range(begin_ptr_ + off);
		}

		friend string_const_range operator+(difference_type off, const string_const_range& right)
		{
			return string_const_range(off + right.begin_ptr_);
		}

		//string_const_range& operator-=(difference_type off)
		//{
		//	begin_ptr_ -= off;
		//	return *this;
		//}

		//string_const_range operator-(difference_type off) const
		//{
		//	return string_const_range(begin_ptr_ - off);
		//}

		//difference_type operator-(const string_const_range& right) const
		//{
		//	return begin_ptr_ - right.begin_ptr_;
		//}

		//Comparison operators
		bool operator==   (const string_const_range& r)  const
		{
			return begin_ptr_ == r.begin_ptr_;
		}

		bool operator!=   (const string_const_range& r)  const
		{
			return begin_ptr_ != r.begin_ptr_;
		}

		bool operator<    (const string_const_range& r)  const
		{
			return begin_ptr_ < r.begin_ptr_;
		}

		bool operator<=   (const string_const_range& r)  const
		{
			return begin_ptr_ <= r.begin_ptr_;
		}

		bool operator>    (const string_const_range& r)  const
		{
			return begin_ptr_ > r.begin_ptr_;
		}

		bool operator>=   (const string_const_range& r)  const
		{
			return begin_ptr_ >= r.begin_ptr_;
		}
	};

	//! Iterator used to iterate through a string
	template <class Pointer>
	class string_range
		:  public string_const_range<Pointer>
	{
	public:
		explicit string_range(Pointer begin_ptr, Pointer end_ptr)
			: string_const_range<Pointer>(begin_ptr, end_ptr)
		{}

	public:
		typedef std::random_access_iterator_tag                                       iterator_category;
		typedef typename boost::intrusive::pointer_traits<Pointer>::element_type      value_type;
		typedef typename boost::intrusive::pointer_traits<Pointer>::difference_type   difference_type;
		typedef Pointer                                                               pointer;
		typedef value_type&                                                           reference;

		//Constructors
		string_range()
		{}

		//Pointer like operators
		reference operator*()  const  
		{
			return *this->begin_ptr_;
		}

		value_type* operator->() const  
		{
			return container_detail::to_raw_pointer(this->begin_ptr_);
		}

		reference operator[](difference_type off) const 
		{
			return this->begin_ptr_[off];
		}

		//Increment / Decrement
		string_range& operator++()  
		{
			++this->begin_ptr_;
			return *this;
		}

		string_range operator++(int)
		{
			pointer tmp = this->begin_ptr_;
			++*this;
			return string_range(tmp);
		}

		string_range& operator--()
		{
			--this->begin_ptr_;
			return *this;
		}

		string_range operator--(int)
		{
			string_range tmp = *this;
			--*this;
			return string_range(tmp);
		}

		// Arithmetic
		string_range& operator+=(difference_type off)
		{
			this->begin_ptr_ += off;
			return *this;
		}

		string_range operator+(difference_type off) const
		{
			return string_range(this->begin_ptr_ + off);
		}

		friend string_range operator+(difference_type off, const string_range& right)
		{
			return string_range(off + right.begin_ptr_);
		}

		string_range& operator-=(difference_type off)
		{
			this->begin_ptr_ -= off;
			return *this;
		}

		string_range operator-(difference_type off) const
		{ 
			return string_range(this->begin_ptr_ - off);
		}

		difference_type operator-(const string_const_range<Pointer>& right) const
		{ 
			return static_cast<const string_const_range<Pointer>&>(*this) - right;
		}
	};

	//template <class T, class A>
	//struct string_value_traits
	//{
	//	typedef T value_type;
	//	typedef A allocator_type;
	//	static const bool trivial_dctr = boost::has_trivial_destructor<value_type>::value;
	//	static const bool trivial_dctr_after_move = trivial_dctr;
	//	//::boost::has_trivial_destructor_after_move<value_type>::value || trivial_dctr;
	//	//static const bool trivial_copy = has_trivial_copy<value_type>::value;
	//	//static const bool nothrow_copy = has_nothrow_copy<value_type>::value;
	//	//static const bool trivial_assign = has_trivial_assign<value_type>::value;
	//	//static const bool nothrow_assign = has_nothrow_assign<value_type>::value;
	//
	//	static const bool trivial_copy = has_trivial_copy<value_type>::value;
	//	static const bool nothrow_copy = has_nothrow_copy<value_type>::value;
	//	static const bool trivial_assign = has_trivial_assign<value_type>::value;
	//	static const bool nothrow_assign = false;
	//
	//	//This is the anti-exception array destructor
	//	//to deallocate values already constructed
	//	typedef typename container_detail::if_c
	//		<trivial_dctr
	//		,container_detail::null_scoped_destructor_n<A>
	//		,container_detail::scoped_destructor_n<A>
	//		>::type   OldArrayDestructor;
	//	//This is the anti-exception array destructor
	//	//to destroy objects created with copy construction
	//	typedef typename container_detail::if_c
	//		<nothrow_copy
	//		,container_detail::null_scoped_destructor_n<A>
	//		,container_detail::scoped_destructor_n<A>
	//		>::type   ArrayDestructor;
	//	//This is the anti-exception array deallocator
	//	typedef typename container_detail::if_c
	//		<nothrow_copy
	//		,container_detail::null_scoped_array_deallocator<A>
	//		,container_detail::scoped_array_deallocator<A>
	//		>::type   ArrayDeallocator;
	//};

	////!This struct deallocates and allocated memory
	//template <class A>
	//struct string_alloc_holder 
	//{
	//	typedef boost::container::allocator_traits<A>         allocator_traits_type;
	//	typedef typename allocator_traits_type::pointer       pointer;
	//	typedef typename allocator_traits_type::size_type     size_type;
	//	typedef typename allocator_traits_type::value_type    value_type;
	//	typedef string_value_traits<value_type, A>            value_traits;
	//
	//	//Constructor, does not throw
	//	string_alloc_holder()
	//		BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor<A>::value)
	//		: members_()
	//	{}
	//
	//	//Constructor, does not throw
	//	template<class AllocConvertible>
	//	explicit string_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT
	//		: members_(boost::forward<AllocConvertible>(a))
	//	{}
	//
	//	//Destructor
	//	~string_alloc_holder()
	//	{
	//		this->prot_destroy_all();
	//		this->prot_deallocate();
	//	}
	//
	//	typedef container_detail::integral_constant<unsigned, 1>      allocator_v1;
	//	typedef container_detail::integral_constant<unsigned, 2>      allocator_v2;
	//	typedef container_detail::integral_constant<unsigned,
	//		boost::container::container_detail::version<A>::value> alloc_version;
	//	std::pair<pointer, bool>
	//		allocation_command(allocation_type command,
	//		size_type limit_size, 
	//		size_type preferred_size,
	//		size_type &received_size, const pointer &reuse = 0)
	//	{
	//		return allocation_command(command, limit_size, preferred_size,
	//			received_size, reuse, alloc_version());
	//	}
	//
	//	std::pair<pointer, bool>
	//		allocation_command(allocation_type command,
	//		size_type limit_size, 
	//		size_type preferred_size,
	//		size_type &received_size,
	//		const pointer &reuse,
	//		allocator_v1)
	//	{
	//		(void)limit_size;
	//		(void)reuse;
	//		if(!(command & allocate_new))
	//			return std::pair<pointer, bool>(pointer(0), false);
	//		received_size = preferred_size;
	//		return std::make_pair(this->alloc().allocate(received_size), false);
	//	}
	//
	//	std::pair<pointer, bool>
	//		allocation_command(allocation_type command,
	//		size_type limit_size, 
	//		size_type preferred_size,
	//		size_type &received_size,
	//		const pointer &reuse,
	//		allocator_v2)
	//	{
	//		return this->alloc().allocation_command
	//			(command, limit_size, preferred_size, received_size, reuse);
	//	}
	//
	//	size_type next_capacity(size_type additional_objects) const
	//	{
	//		return get_next_capacity( allocator_traits_type::max_size(this->alloc())
	//			, this->members_.m_capacity, additional_objects);
	//	}
	//
	//	struct members_holder
	//		: public A
	//	{
	//	private:
	//		members_holder(const members_holder&);
	//
	//	public:
	//		template<class Alloc>
	//		explicit members_holder(BOOST_FWD_REF(Alloc) alloc)
	//			:  A(boost::forward<Alloc>(alloc)), m_start(0), m_size(0), m_capacity(0)
	//		{}
	//
	//		members_holder()
	//			:  A(), m_start(0), m_size(0), m_capacity(0)
	//		{}
	//
	//		pointer     m_start;
	//		size_type   m_size;
	//		size_type   m_capacity;
	//	} members_;
	//
	//	void swap_members(string_alloc_holder &x)
	//	{
	//		container_detail::do_swap(this->members_.m_start, x.members_.m_start);
	//		container_detail::do_swap(this->members_.m_size, x.members_.m_size);
	//		container_detail::do_swap(this->members_.m_capacity, x.members_.m_capacity);
	//	}
	//
	//	A &alloc()
	//	{  return members_;  }
	//
	//	const A &alloc() const
	//	{  return members_;  }
	//
	//protected:
	//	void prot_deallocate()
	//	{
	//		if(!this->members_.m_capacity)   return;
	//		this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity);
	//		this->members_.m_start     = 0;
	//		this->members_.m_size      = 0;
	//		this->members_.m_capacity  = 0;
	//	}
	//
	//	void destroy(value_type* p)
	//	{
	//		if(!value_traits::trivial_dctr)
	//			allocator_traits_type::destroy(this->alloc(), p);
	//	}
	//
	//	void destroy_n(value_type* p, size_type n)
	//	{
	//		if(!value_traits::trivial_dctr){
	//			for(; n--; ++p){
	//				allocator_traits_type::destroy(this->alloc(), p);
	//			}
	//		}
	//	}
	//
	//	void prot_destroy_all()
	//	{
	//		this->destroy_n(container_detail::to_raw_pointer(this->members_.m_start), this->members_.m_size);
	//		this->members_.m_size = 0;
	//	}
	//};


} //namespace container_detail
} //namespace container {
} // namespace boost {


#endif // string_range_HPP__

